import { Observable, Subject } from 'rxjs'

/**
 * 设计器命令接口
 * 所有设计器命令都应实现此接口
 */
export interface DesignerCommand {
  /**
   * 命令的唯一标识符
   */
  readonly id: string
  
  /**
   * 执行命令
   * @returns 命令执行结果
   */
  execute(): any
  
  /**
   * 撤销命令
   * @returns 撤销结果
   */
  undo(): any
  
  /**
   * 命令是否可撤销
   */
  readonly canUndo: boolean
}

/**
 * 命令执行器接口
 * 负责执行、撤销和重做命令
 */
export interface CommandExecutor {
  /**
   * 执行命令
   * @param command 要执行的命令
   * @returns 命令执行结果
   */
  execute(command: DesignerCommand): any
  
  /**
   * 撤销上一个命令
   * @returns 撤销结果
   */
  undo(): any
  
  /**
   * 重做上一个被撤销的命令
   * @returns 重做结果
   */
  redo(): any
  
  /**
   * 是否可以撤销
   */
  readonly canUndo: boolean
  
  /**
   * 是否可以重做
   */
  readonly canRedo: boolean
  
  /**
   * 命令执行后的事件流
   */
  readonly commandExecuted$: Observable<DesignerCommand>
  
  /**
   * 命令撤销后的事件流
   */
  readonly commandUndone$: Observable<DesignerCommand>
  
  /**
   * 命令重做后的事件流
   */
  readonly commandRedone$: Observable<DesignerCommand>
}

/**
 * 标准命令执行器实现
 * 提供命令的执行、撤销、重做功能
 */
export class StandardCommandInvoker implements CommandExecutor {
  private undoStack: DesignerCommand[] = []
  private redoStack: DesignerCommand[] = []
  
  private commandExecutedSubject = new Subject<DesignerCommand>()
  private commandUndoneSubject = new Subject<DesignerCommand>()
  private commandRedoneSubject = new Subject<DesignerCommand>()
  
  /**
   * 命令执行后的事件流
   */
  readonly commandExecuted$ = this.commandExecutedSubject.asObservable()
  
  /**
   * 命令撤销后的事件流
   */
  readonly commandUndone$ = this.commandUndoneSubject.asObservable()
  
  /**
   * 命令重做后的事件流
   */
  readonly commandRedone$ = this.commandRedoneSubject.asObservable()
  
  /**
   * 执行命令
   * @param command 要执行的命令
   * @returns 命令执行结果
   */
  execute(command: DesignerCommand): any {
    const result = command.execute()
    
    if (command.canUndo) {
      this.undoStack.push(command)
      this.redoStack = [] // 清空重做栈
    }
    
    this.commandExecutedSubject.next(command)
    return result
  }
  
  /**
   * 撤销上一个命令
   * @returns 撤销结果
   */
  undo(): any {
    if (!this.canUndo) {
      return null
    }
    
    const command = this.undoStack.pop()!
    const result = command.undo()
    
    this.redoStack.push(command)
    this.commandUndoneSubject.next(command)
    
    return result
  }
  
  /**
   * 重做上一个被撤销的命令
   * @returns 重做结果
   */
  redo(): any {
    if (!this.canRedo) {
      return null
    }
    
    const command = this.redoStack.pop()!
    const result = command.execute()
    
    this.undoStack.push(command)
    this.commandRedoneSubject.next(command)
    
    return result
  }
  
  /**
   * 是否可以撤销
   */
  get canUndo(): boolean {
    return this.undoStack.length > 0
  }
  
  /**
   * 是否可以重做
   */
  get canRedo(): boolean {
    return this.redoStack.length > 0
  }
  
  /**
   * 清空撤销和重做栈
   */
  clear(): void {
    this.undoStack = []
    this.redoStack = []
  }
}